package com.lagou.handler;

import com.alibaba.fastjson.JSON;
import com.lagou.boot.SpringContextHolder;
import com.lagou.rpc.RpcRequest;
import org.apache.commons.beanutils.ConvertUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 自定义的业务处理器
 */
public class UserServiceHandler extends ChannelInboundHandlerAdapter {

    //当客户端读取数据时,该方法会被调用
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //获取 对象
        RpcRequest rpcRequest = JSON.parseObject(msg.toString(), RpcRequest.class);
        //获取容器
        ApplicationContext context = SpringContextHolder.getApplicationContext();

        Object bean = context.getBean(rpcRequest.getRequestId());
        Method method = getMethod(bean.getClass(), rpcRequest.getMethodName());
        if (method ==null){
            throw new RuntimeException(String.format( "读取入参为%s,方法获取失败!",rpcRequest));
        }
        //获取方法参数
        List<Object> paramList = getMethodParamList(rpcRequest.getParameters(), rpcRequest.getParameterTypes());
        //执行
        Object o = method.invoke(bean, paramList);

        //写入客户端
        ctx.writeAndFlush(o);
    }



    /**
     * 获取方法实际参数，不支持基本类型
     */
    private List<Object> getMethodParamList(Object[] paramMap, Class<?>[] parameterTypes) throws Exception {
        List<Object> objectList = new ArrayList<>();
        for (int i = 0; i < paramMap.length; i++) {
            Object convert = ConvertUtils.convert(paramMap[i], parameterTypes[i]);
            objectList.add(convert);
        }
        return objectList;
    }

    /**
     * 获取目标方法
     * @param proxyObject
     * @param methodStr
     * @return
     */
    private Method getMethod(Class proxyObject, String methodStr) {
        Method[] methods = proxyObject.getMethods();

        for(Method method : methods) {
            if(method.getName().equalsIgnoreCase(methodStr)) {
                return method;
            }
        }

        return null;
    }
}
